package models

import (
	"context"
	"fmt"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
	"strings"
	"time"
	"zbn-oil-consumption/config"
	"zbn-oil-consumption/utils"
)

type Record struct {
	Id         *bson.ObjectID `bson:"_id,omitempty" json:"id"`
	UserId     int64          `bson:"user_id" json:"userId"`
	Username   string         `bson:"username" json:"username"`
	Amount     int64          `bson:"amount" json:"amount"`
	Mileage    int64          `bson:"mileage" json:"mileage"`
	OilVolume  int64          `bson:"oil_volume" json:"oilVolume"`
	OilPrice   float32        `bson:"oil_price" json:"oilPrice"`
	GasStation string         `bson:"gas_station" json:"gasStation"`
	RefuelDate string         `bson:"refuel_date" json:"refuelDate"`
	Remark     string         `bson:"remark" json:"remark"`
	CreatedAt  time.Time      `bson:"created_at" json:"createdAt"`
}

type TotalValue struct {
	Total int `bson:"total"`
}

func (r Record) Add(record Record) (id any, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	res, err := c.InsertOne(ctx, record)
	if err != nil {
		return
	}
	id = res.InsertedID
	return
}

func (Record) UpdateById(data Record) (id int64, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	filter := bson.M{"_id": data.Id}
	update := bson.M{
		"$set": bson.M{
			"amount":      data.Amount,
			"mileage":     data.Mileage,
			"oil_volume":  data.OilVolume,
			"oil_price":   data.OilPrice,
			"gas_station": data.GasStation,
			"refuel_date": data.RefuelDate,
			"remark":      data.Remark,
		},
	}
	res, err := c.UpdateOne(ctx, filter, update)
	if err != nil {
		return
	}
	id = res.ModifiedCount
	return
}

func (r Record) FindByUserId(userId int64) (res []Record, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	filter := bson.M{"user_id": userId}
	// 执行查询
	cursor, err := c.Find(ctx, filter)
	if err != nil {
		return
	}
	defer cursor.Close(ctx)
	err = cursor.All(ctx, &res)
	return
}

func (r Record) FindById(Id bson.ObjectID) (res Record, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	filter := bson.M{"_id": Id}
	// 执行查询
	err = c.FindOne(ctx, filter).Decode(&res)
	if err != nil {
		return
	}
	return
}

func (r Record) FindLastByUserId(userId int64) (res Record, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	filter := bson.M{"user_id": userId}
	opts := options.FindOne().
		SetSort(bson.D{{"created_at", -1}}) // -1表示降序，1表示升序
	// 执行查询
	err = c.FindOne(ctx, filter, opts).Decode(&res)
	if err != nil {
		return
	}
	return
}

func (Record) GetList(params utils.Params) (total int64, res []Record, err error) {
	ctx := context.Background()
	skip := (params.Page - 1) * params.PageSize
	findOptions := options.Find()
	findOptions.SetSkip(int64(skip))
	findOptions.SetLimit(int64(params.PageSize))
	filter := bson.M{}
	if strings.TrimSpace(params.Username) != "" {
		filter["username"] = strings.TrimSpace(params.Username)
	}
	c := config.Db.Collection("records")
	total, err = c.CountDocuments(ctx, filter)
	if err != nil {
		return 0, nil, err
	}
	// 执行查询
	cursor, err := c.Find(ctx, filter, findOptions)
	if err != nil {
		return 0, nil, fmt.Errorf("find failed: %w", err)
	}
	defer cursor.Close(ctx)
	err = cursor.All(ctx, &res)
	return
}

func (Record) GetListByMonth(params utils.Params) (total int64, res []Record, err error) {
	ctx := context.Background()
	skip := (params.Page - 1) * params.PageSize
	findOptions := options.Find()
	findOptions.SetSkip(int64(skip))
	findOptions.SetLimit(int64(params.PageSize))

	filter := bson.M{}

	if params.Month != "" {
		month, _ := time.Parse("2006-01", params.Month)
		startOfMonth := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
		endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond)
		filter = bson.M{"user_id": params.UserId,
			"created_at": bson.M{
				"$gte": startOfMonth,
				"$lt":  endOfMonth,
			}}
	} else {
		filter = bson.M{"user_id": params.UserId}
	}

	c := config.Db.Collection("records")
	total, err = c.CountDocuments(ctx, filter)
	if err != nil {
		return 0, nil, err
	}
	// 执行查询
	cursor, err := c.Find(ctx, filter, findOptions)
	if err != nil {
		return 0, nil, fmt.Errorf("find failed: %w", err)
	}
	defer cursor.Close(ctx)
	err = cursor.All(ctx, &res)
	return
}

func (r Record) TotalByUserId(userId int64, fieldName string) (res int, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	// 执行查询
	pipeline := []bson.M{
		{"$match": bson.M{"user_id": userId}},
		{
			"$group": bson.M{
				"_id": nil,
				"total": bson.M{
					"$sum": "$" + fieldName,
				},
			},
		},
	}

	cursor, err := c.Aggregate(ctx, pipeline)
	if err != nil {
		return 0, err
	}
	defer cursor.Close(ctx)

	var result TotalValue

	if cursor.Next(ctx) {
		if err := cursor.Decode(&result); err != nil {
			return 0, err
		}
		return result.Total, nil
	}

	return 0, nil
}

func (r Record) TotalByUserIdCurrentMonth(userId int64, fieldName string) (res int, err error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	// 执行查询
	now := time.Now()
	startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
	endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond)

	pipeline := []bson.M{
		{"$match": bson.M{
			"user_id": userId,
			"created_at": bson.M{
				"$gte": startOfMonth,
				"$lt":  endOfMonth,
			},
		}},
		{
			"$group": bson.M{
				"_id": nil,
				"total": bson.M{
					"$sum": "$" + fieldName,
				},
			},
		},
	}

	cursor, err := c.Aggregate(ctx, pipeline)
	if err != nil {
		return 0, err
	}
	defer cursor.Close(ctx)

	var result TotalValue

	if cursor.Next(ctx) {
		if err := cursor.Decode(&result); err != nil {
			return 0, err
		}
		return result.Total, nil
	}
	return 0, nil
}

func (r Record) MaxByUserId(userId int64, fieldName string) (interface{}, error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	// 执行查询
	pipeline := []bson.M{
		{"$match": bson.M{"user_id": userId}},
		{
			"$group": bson.M{
				"_id": nil,
				"maxValue": bson.M{
					"$max": "$" + fieldName,
				},
			},
		},
	}

	cursor, err := c.Aggregate(ctx, pipeline)
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var results []bson.M
	if err := cursor.All(ctx, &results); err != nil {
		return nil, err
	}

	if len(results) == 0 {
		return nil, fmt.Errorf("no documents found")
	}

	return results[0]["maxValue"], nil
}

func (r Record) MinByUserId(userId int64, fieldName string) (interface{}, error) {
	ctx := context.Background()
	c := config.Db.Collection("records")
	// 执行查询
	pipeline := []bson.M{
		{"$match": bson.M{"user_id": userId}},
		{
			"$group": bson.M{
				"_id": nil,
				"minValue": bson.M{
					"$min": "$" + fieldName,
				},
			},
		},
	}

	cursor, err := c.Aggregate(ctx, pipeline)
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var results []bson.M
	if err := cursor.All(ctx, &results); err != nil {
		return nil, err
	}

	if len(results) == 0 {
		return nil, fmt.Errorf("no documents found")
	}

	return results[0]["minValue"], nil
}
